package com.demo.java.reflect;


import com.esotericsoftware.reflectasm.ConstructorAccess;
import com.esotericsoftware.reflectasm.MethodAccess;

import java.lang.reflect.Constructor;
import java.lang.reflect.Method;

public class ReflectAsmTest {
    private static class Person {
        private String name;
        public Person() {}
        public Person(String name) {
            this.name = name;
        }
        public String sayHello() {
            return "hello: " + name;
        }

        public String getName() {
            return name;
        }

        public void setName(String name) {
            this.name = name;
        }
    }

    public static void jdkInstanceTest(long testNum) {
        long t1 = System.currentTimeMillis();
        Person person = null;
        for (int i = 0; i < testNum; i++) {
            person = new Person("zhangsan");
        }
        person.sayHello();
        long t2 = System.currentTimeMillis();
        System.out.println("jdk Instance test cost: " + (t2 - t1));
    }
    public static void jdkMethodInvokeTest(long testNum) {
        long t1 = System.currentTimeMillis();
        Person person = new Person("zhangsan");
        for (int i = 0; i < testNum; i++) {
            person.sayHello();
        }
        long t2 = System.currentTimeMillis();
        System.out.println("jdk method invoke test cost: " + (t2 - t1));
    }

    public static void jdkReflectInstanceTest(long testNum) throws Exception {
        Class clazz = Class.forName(Person.class.getName());
        Constructor constructor = clazz.getDeclaredConstructor(new Class[]{String.class});
        long t1 = System.currentTimeMillis();
        Person person = null;
        for (int i = 0; i < testNum; i++) {
            person = (Person) constructor.newInstance("zhangsan");
        }
        person.sayHello();
        long t2 = System.currentTimeMillis();
        System.out.println("jdk reflect instance test cost: " + (t2 - t1));
    }
    public static void jdkReflectMethodInvokeTest(long testNum) throws Exception {
        Class clazz = Class.forName(Person.class.getName());
        Person person = null;
        Constructor constructor = clazz.getDeclaredConstructor(new Class[]{String.class});
        person = (Person) constructor.newInstance("zhangsan");
        long t1 = System.currentTimeMillis();
        for (int i = 0; i < testNum; i++) {
            Method method = clazz.getDeclaredMethod("sayHello", new Class[]{});
            method.invoke(person);
        }
        person.sayHello();
        long t2 = System.currentTimeMillis();
        System.out.println("jdk reflect method invoke test cost: " + (t2 - t1));
    }

    public static void asmReflectInstanceTest(long testNum) {
        ConstructorAccess<Person> ca = ConstructorAccess.get(Person.class);
        MethodAccess ma = MethodAccess.get(Person.class);
        long t1 = System.currentTimeMillis();
        for (int i = 0; i < testNum; i++) {
            Person obj = ca.newInstance();
            obj.setName("zhangsan");
        }
        long t2 = System.currentTimeMillis();
        System.out.println("asm reflect instance test cost: " + (t2 - t1));
    }
    public static void asmReflectMethodInvokeTest(long testNum) {
        ConstructorAccess<Person> ca = ConstructorAccess.get(Person.class);
        MethodAccess ma = MethodAccess.get(Person.class);
        Person obj = ca.newInstance();
        obj.setName("zhangsan");
        long t1 = System.currentTimeMillis();
        for (int i = 0; i < testNum; i++) {
            ma.invoke(obj, "sayHello");
        }
        long t2 = System.currentTimeMillis();
        System.out.println("asm reflect method invoke test cost: " + (t2 - t1));
    }
    public static void main(String[] args) throws Exception {
        long testNum = 50000000;

        jdkInstanceTest(testNum);
        jdkMethodInvokeTest(testNum);
        jdkReflectInstanceTest(testNum);
        jdkReflectMethodInvokeTest(testNum);
        asmReflectInstanceTest(testNum);
        asmReflectMethodInvokeTest(testNum);

        /**
         jdk Instance test cost: 608
         jdk method invoke test cost: 2879
         jdk reflect instance test cost: 740
         jdk reflect method invoke test cost: 13369
         asm reflect instance test cost: 68
         asm reflect method invoke test cost: 1100

         jdk Instance test cost: 703
         jdk method invoke test cost: 4480
         jdk reflect instance test cost: 1309
         jdk reflect method invoke test cost: 29105
         asm reflect instance test cost: 280
         asm reflect method invoke test cost: 1429

         jdk Instance test cost: 640
         jdk method invoke test cost: 3300
         jdk reflect instance test cost: 961
         jdk reflect method invoke test cost: 13716
         asm reflect instance test cost: 57
         asm reflect method invoke test cost: 1329
         */
    }
}

